﻿#include "driverservice.h"

DriverService::DriverService()
{

}
/*++
Routine Description:
Arguments:
Return Value:
--*/
BOOLEAN DriverService::InstallDriver(
        IN SC_HANDLE  SchSCManager,
        IN LPCTSTR    DriverName,
        IN LPCTSTR    ServiceExe
        )

{
    SC_HANDLE   schService;
    // NOTE: This creates an entry for a standalone driver. If this
    //       is modified for use with a driver that requires a Tag,
    //       Group, and/or Dependencies, it may be necessary to
    //       query the registry for existing driver information
    //       (in order to determine a unique Tag, etc.).

    //
    // Create a new a service object.
    schService = CreateService(SchSCManager,           // handle of service control manager database
                               DriverName,             // address of name of service to start
                               DriverName,             // address of display name
                               SERVICE_ALL_ACCESS,     // type of access to service
                               SERVICE_KERNEL_DRIVER,  // type of service
                               SERVICE_DEMAND_START,   // when to start service
                               SERVICE_ERROR_NORMAL,   // severity if service fails to start
                               ServiceExe,             // address of name of binary file
                               NULL,                   // service does not belong to a group
                               NULL,                   // no tag requested
                               NULL,                   // no dependency names
                               NULL,                   // use LocalSystem account
                               NULL                    // no password for service account
                               );

    if (schService == NULL) {
        err = GetLastError();
        if (err == ERROR_SERVICE_EXISTS) {
            // Ignore this error.
            return TRUE;
        } else {
            qDebug()<<"CreateService failed!  Error = "<< err;
            // Indicate an error.
            return FALSE;
        }
    }
    // Close the service object.
    if (schService) {
        CloseServiceHandle(schService);
    }
    // Indicate success.
    return TRUE;
}   // InstallDriver


BOOLEAN DriverService::RemoveDriver(
        IN SC_HANDLE  SchSCManager,
        IN LPCTSTR    DriverName
        )
{
    SC_HANDLE   schService;
    BOOLEAN     rCode;
    // Open the handle to the existing service.
    schService = OpenService(SchSCManager,
                             DriverName,
                             SERVICE_ALL_ACCESS
                             );
    if (schService == NULL) {
        err = GetLastError();
        qDebug()<<"OpenService failed!  Error = "<< err;
        // Indicate error.
        return FALSE;
    }
    // Mark the service for deletion from the service control manager database.
    if (DeleteService(schService)) {
        // Indicate success.
        rCode = TRUE;
    } else {
        err = GetLastError();
        qDebug()<< "DeleteService failed!  Error =  "<< err;
        // Indicate failure.  Fall through to properly close the service handle.
        rCode = FALSE;
    }
    // Close the service object.
    if (schService) {
        CloseServiceHandle(schService);
    }
    return rCode;
}   // RemoveDriver

BOOLEAN DriverService::StartDriver(
        IN SC_HANDLE  SchSCManager,
        IN LPCTSTR    DriverName
        )
{
    SC_HANDLE   schService;
    // Open the handle to the existing service.
    schService = OpenService(SchSCManager,DriverName,SERVICE_ALL_ACCESS);
    if (schService == NULL) {
        err = GetLastError();
        qDebug()<< "OpenService failed!  Error =  "<< err;
        // Indicate failure.
        return FALSE;
    }
    // Start the execution of the service (i.e. start the driver).
    if (!StartService(schService,     // service identifier
                      0,              // number of arguments
                      NULL            // pointer to arguments
                      )) {
        err = GetLastError();
        if (err == ERROR_SERVICE_ALREADY_RUNNING) {
            // Ignore this error.
            return TRUE;
        } else {
            qDebug()<<"StartService failure! Error =  "<< err;
            // Indicate failure.  Fall through to properly close the service handle.
            return FALSE;
        }
    }
    // Close the service object.
    if (schService) {
        CloseServiceHandle(schService);
    }
    return TRUE;
}   // StartDriver

BOOLEAN DriverService::StopDriver(
        IN SC_HANDLE  SchSCManager,
        IN LPCTSTR    DriverName
        )
{
    BOOLEAN         rCode = TRUE;
    SC_HANDLE       schService;
    SERVICE_STATUS  serviceStatus;
    // Open the handle to the existing service.
    schService = OpenService(SchSCManager,
                             DriverName,
                             SERVICE_ALL_ACCESS
                             );
    if (schService == NULL) {
        err = GetLastError();
        qDebug()<< "OpenService failed!  Error:  "<<err;
        return FALSE;
    }
    // Request that the service stop.
    if (ControlService(schService,SERVICE_CONTROL_STOP,&serviceStatus)) {
        // Indicate success.
        rCode = TRUE;
    } else {
        err = GetLastError();
        qDebug()<< "ControlService failed!  Error =  "<<err;
        // Indicate failure.  Fall through to properly close the service handle.
        rCode = FALSE;
    }
    // Close the service object.
    if (schService) {
        CloseServiceHandle (schService);
    }
    return rCode;
}   //  StopDriver

BOOLEAN DriverService::ManageDriver(
        IN LPCTSTR  DriverName,
        IN LPCTSTR  ServiceName,
        IN USHORT   Function
        )
{
    err = GetLastError();
    SC_HANDLE   schSCManager;
    BOOLEAN rCode = TRUE;
    // Insure (somewhat) that the driver and service names are valid.
    if (!DriverName || !ServiceName) {
        qDebug()<<"Invalid Driver or Service provided to ManageDriver()  ";
        return FALSE;
    }
    // Connect to the Service Control Manager and open the Services database.
    schSCManager = OpenSCManager(NULL,                   // local machine
                                 NULL,                   // local database
                                 SC_MANAGER_ALL_ACCESS   // access required
                                 );
    if (!schSCManager) {
        qDebug()<< "Open SC Manager failed! Error = "<< GetLastError();
        return FALSE;
    }
    // Do the requested function.
    switch( Function ) {
    case DRIVER_FUNC_INSTALL:
        // Install the driver service.
        if (this->InstallDriver(schSCManager,DriverName,ServiceName)) {
            // Start the driver service (i.e. start the driver).
            rCode = this->StartDriver(schSCManager,DriverName);
        } else {
            // Indicate an error.
            rCode = FALSE;
        }
        break;
    case DRIVER_FUNC_REMOVE:
        // Stop the driver.
        this->StopDriver(schSCManager,DriverName);
        // Remove the driver service.
        this->RemoveDriver(schSCManager,DriverName );
        // Ignore all errors.
        rCode = TRUE;
        break;
    default:
        qDebug()<<("Unknown ManageDriver() function");
        rCode = FALSE;
        break;
    }
    // Close handle to service control manager.
    if (schSCManager) {
        CloseServiceHandle(schSCManager);
    }
    return rCode;

}   // ManageDriver
ULONG DriverService::GetDriverManagerLastErrorCode()
{
    return err;
}
